#include "controls/spinbox/cxispinbox.h"
#include "private/spinbox/cxispinbox_p.h"

#include <QApplication>
#include <QKeyEvent>
#include <QLineEdit>

CxiSpinBox::CxiSpinBox(QWidget* parent)
	: QLineEdit(parent), d_ptr(new CxiSpinBoxPrivate(this))
{
	setAttribute(Qt::WA_InputMethodEnabled, false);
}

CxiSpinBox::~CxiSpinBox()
{
	delete d_ptr;
}

void CxiSpinBox::setIsAllowNegativeNumber(bool allow)
{
	Q_D(CxiSpinBox);
	d->isAllowNegativeNumber = allow;
}
bool CxiSpinBox::isAllowNegativeNumber() const
{
	Q_D(const CxiSpinBox);
	return d->isAllowNegativeNumber;
}

void CxiSpinBox::setIsString(bool s)
{
	Q_D(CxiSpinBox);
	d->isString = s;
}
bool CxiSpinBox::isString() const
{
	Q_D(const CxiSpinBox);
	return d->isString;
}

void CxiSpinBox::setIsDecimal(bool dec)
{
	Q_D(CxiSpinBox);
	d->isDecimal = dec;
}
bool CxiSpinBox::isDecimal() const
{
	Q_D(const CxiSpinBox);
	return d->isDecimal;
}

void CxiSpinBox::setFormatStyle(FormatStyle style)
{
	Q_D(CxiSpinBox);
	d->formatStyle = style;
}
CxiSpinBox::FormatStyle CxiSpinBox::formatStyle() const
{
	Q_D(const CxiSpinBox);
	return d->formatStyle;
}

void CxiSpinBox::setNumberEditorStyle(NumberEditorStyle style)
{
	Q_D(CxiSpinBox);
	if (d->numberEditorStyle == style)
		return;
	d->numberEditorStyle = style;
	d->updateNumberEditorStyle();
}
CxiSpinBox::NumberEditorStyle CxiSpinBox::numberEditorStyle() const
{
	Q_D(const CxiSpinBox);
	return d->numberEditorStyle;
}

void CxiSpinBox::setIncrement(double inc)
{
	Q_D(CxiSpinBox);
	if (inc <= 0)
	{
		return;
	}
	d->increment = inc;
}
qreal CxiSpinBox::increment() const
{
	Q_D(const CxiSpinBox);
	return d->increment;
}

QVariant CxiSpinBox::value() const
{
	Q_D(const CxiSpinBox);
	if (d->isDecimal)
	{
		return d->value.toDouble();
	}
	return d->value.toInt();
}

void CxiSpinBox::setValue(const QVariant& value)
{
	Q_D(CxiSpinBox);
	d->value = value;
}
void CxiSpinBox::resizeEvent(QResizeEvent* event)
{
	Q_D(CxiSpinBox);
	QLineEdit::resizeEvent(event);
	d->layoutButtons();
}

void CxiSpinBox::setMinimum(const QVariant& minimum)
{
	Q_D(CxiSpinBox);
	d->minimum = minimum;
}
QVariant CxiSpinBox::minimum() const
{
	Q_D(const CxiSpinBox);
	if (d->isDecimal)
	{
		return d->minimum.toDouble();
	}
	return d->minimum.toInt();
}
void CxiSpinBox::setMaximum(const QVariant& maximum)
{
	Q_D(CxiSpinBox);
	d->maximum = maximum;
}
QVariant CxiSpinBox::maximum() const
{
	Q_D(const CxiSpinBox);
	if (d->isDecimal)
	{
		return d->maximum.toDouble();
	}
	return d->maximum.toInt();
}

int CxiSpinBox::decimal() const
{
	Q_D(const CxiSpinBox);
	return d->decimal;
}
void CxiSpinBox::setDecimal(int decimal)
{
	Q_D(CxiSpinBox);
	d->decimal = decimal;
}

void CxiSpinBox::keyPressEvent(QKeyEvent* event)
{
	Q_D(CxiSpinBox);

	int key = event->key();
	QString currentText = text();
	int cursorPos = cursorPosition();

	const bool isNumberKey = (key >= Qt::Key_0 && key <= Qt::Key_9);
	const bool isDecimalPoint = (key == Qt::Key_Period);
	const bool isMinus = (key == Qt::Key_Minus);
	const bool isControl = (key == Qt::Key_Backspace || key == Qt::Key_Delete ||
							key == Qt::Key_Left || key == Qt::Key_Right);
	const bool isConfirm = (key == Qt::Key_Return || key == Qt::Key_Enter);

	if (isConfirm)
	{
		QFocusEvent fakeEvent(QEvent::FocusOut);
		focusOutEvent(&fakeEvent);
		emit valueChanged(value());
		return;
	}

	if (d->isString)
	{
		if (isNumberKey || isControl)
			QLineEdit::keyPressEvent(event);
		else
			event->ignore();
		return;
	}

	if (isNumberKey || isControl)
	{
		QLineEdit::keyPressEvent(event);
		return;
	}

	if (d->isDecimal && isDecimalPoint)
	{
		if (!currentText.contains('.'))
			QLineEdit::keyPressEvent(event);
		else
			event->ignore();
		return;
	}

	if (d->isAllowNegativeNumber && isMinus)
	{
		if (!currentText.contains('-') && cursorPos == 0)
			QLineEdit::keyPressEvent(event);
		else
			event->ignore();
		return;
	}

	event->ignore();
}

void CxiSpinBox::focusInEvent(QFocusEvent* event)
{
	Q_D(CxiSpinBox);
	d->onFocusIn(event);
	QLineEdit::focusInEvent(event);
}

void CxiSpinBox::focusOutEvent(QFocusEvent* event)
{
	Q_D(CxiSpinBox);
	d->onFocusOut(event);
	QLineEdit::focusOutEvent(event);
}